/*
 * Created on Feb 7, 2008
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package org.phalanx.server;

import java.sql.SQLException;

import org.phalanx.game.units.ArmyEncampmentUnit;
import org.phalanx.game.units.HeavyScoutUnit;
import org.phalanx.game.units.InfantryUnit;
import org.phalanx.game.units.LightScoutUnit;
import org.phalanx.game.units.PhalanxMapUnit;
import org.phalanx.game.units.PhalanxMapUnitSet;
import org.phalanx.game.units.VillageUnit;
import org.phalanx.logger.SystemLogger;
import org.phalanx.server.ServerCache.CacheManager;
import org.phalanx.server.game.GameListCacheHandler;
import org.phalanx.server.game.GameMoveCacheHandler;
import org.phalanx.server.game.GamePlayersCacheHandler;
import org.phalanx.server.game.PhalanxGameStateCacheHandler;
import org.phalanx.server.game.PhalanxMapCacheHandler;
import org.phalanx.server.game.PhalanxMapManager;
import org.phalanx.server.game.PhalanxPlayerStateCacheHandler;
import org.phalanx.server.properties.ServerPrefXMLReader;
import org.phalanx.server.properties.ServerPreferences;
import org.phalanx.server.social.PhalanxChatRoomManager;
import org.phalanx.server.sql.SQLManager;
import org.phalanx.server.user.UserCacheHandler;

/**
 * @author sday
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class PhalanxServer {
	private static PhalanxServer currentPhalanxServer;
	private ServerPreferences serverPrefs;
	private CacheManager serverCache;
	private SQLManager phalanxSQLManager;
	private SystemLogger serverLogger;
	private PhalanxChatRoomManager chatMgr;
	private String phalanxXMLFile = "";
	String cacheDir;
	String mapDir;
	String defaultTileSet;
	PhalanxMapManager mapMgr;
	private String phalanxRootDirectory;
	private static final Integer majorVersion = 0;
	private static final Integer minorVersion = 1;
	private static final Integer subVersion = 0;
	
	private boolean cachesLoaded = false;
	
	public synchronized static PhalanxServer getServerInstance(){
		return currentPhalanxServer;
	}
	
	public synchronized static void setServerInstance(PhalanxServer newInstance){
		currentPhalanxServer = newInstance;
	}
	
	public PhalanxServer(){}
	
	public PhalanxServer(String prefFilePath){
		this.phalanxXMLFile = prefFilePath;
	}
	
	
	public static void main(String[] args) {
		// Init start up sequence
		currentPhalanxServer = new PhalanxServer();
		currentPhalanxServer.init();
		return;
	}
	
	public void init(){
		/*
		 * Steps for Init()
		 * 1. Grab server properties information
		 * 2. Do sanity check on properties
		 * 3. Initialize Network
		 * 4. Run Server
		 * 
		 * */
		
		setServerPrefs(new ServerPreferences());
		initializeServerPreferencesValues();
		initializeLogging();
		
		serverLogger.writeToConsole("Starting up Phalanx Server v" + formattedVersion() , this, SystemLogger.NORMAL);
		
		if (!initializeSQLPersistence()){
			serverLogger.writeToConsole("SQL Server Error Exiting..." , this, SystemLogger.NORMAL);
			return;
		}
		
		initializeServerCacheManager();
		
		mapMgr = new PhalanxMapManager(this.getCacheManager());
		initializeCaches();
		
		chatMgr = new PhalanxChatRoomManager(this.getCacheManager());
		
		while(true){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException ie){}
		}
	}
	
	public void setMapProperties(String cacheDir, String mapDir, String defaultTileSet){
		this.cacheDir = cacheDir;
		this.mapDir = mapDir;
		this.defaultTileSet = defaultTileSet;
	}
	
	public void setDefaultMapUnitSet(){
		
	}
	
	public void setRootDirectory(String dir){
		phalanxRootDirectory = dir;
	}
	
	public String getRootDirectory(){
		return phalanxRootDirectory;
	}
	
	public PhalanxMapUnitSet createDefaultUnitSet(){
		// For now we will manually create this and later on we will create a game unit set
		// file mechanism much like the tile sets
		
		PhalanxMapUnitSet uSet = new PhalanxMapUnitSet();
		
		String unitsDirectory = phalanxRootDirectory + "/gameunits/";
		
		uSet.addPhalanxMapUnit(new PhalanxMapUnit(new InfantryUnit().getUnitName(), unitsDirectory + "Army1.png"));
		uSet.addPhalanxMapUnit(new PhalanxMapUnit(new VillageUnit().getUnitName(), unitsDirectory + "Village.png"));
		uSet.addPhalanxMapUnit(new PhalanxMapUnit(new LightScoutUnit().getUnitName(), unitsDirectory + "LightScout.png"));
		uSet.addPhalanxMapUnit(new PhalanxMapUnit(new HeavyScoutUnit().getUnitName(), unitsDirectory + "HeavyScout.png"));
		uSet.addPhalanxMapUnit(new PhalanxMapUnit(new ArmyEncampmentUnit().getUnitName(), unitsDirectory + "ArmyCamp.png"));
		
		return uSet;
	}
	
	private void setServerPrefs(ServerPreferences newPref){
		serverPrefs = newPref;
	}
	
	private boolean initializeSQLPersistence(){
		try {
			serverLogger.writeToConsole("Initialize SQL Connection" , this, SystemLogger.NORMAL);
			phalanxSQLManager = new SQLManager(serverPrefs);
			phalanxSQLManager.connect();
		} catch (SQLException se){
			se.printStackTrace();
			return false;
		}
		return true;
	}
	
	public SQLManager getSQLManager(){
		return phalanxSQLManager;
	}
	
	private void initializeServerPreferencesValues(){
		ServerPrefXMLReader serverPreferencesReader;
		
		if (this.phalanxXMLFile.isEmpty()){
			serverPreferencesReader = new ServerPrefXMLReader(getServerPrefs());
		}
		else {
			serverPreferencesReader = new ServerPrefXMLReader(getServerPrefs(), phalanxXMLFile);
		}
		serverPreferencesReader.readXMLIntoPrefs();
	}
	
	private void initializeServerCacheManager(){
		serverCache = new CacheManager();
	}
	
	private void initializeLogging(){
		Integer logLevel = serverPrefs.getPropertiesAsInt("PhalanxServer.Logging.LogLevel", SystemLogger.NORMAL);
		Integer logFileLevel = serverPrefs.getPropertiesAsInt("PhalanxServer.Logging.LogFileLevel", SystemLogger.NORMAL);
		Boolean isLogToFile = serverPrefs.getPropertiesAsBoolean("PhalanxServer.Logging.LogToFile", Boolean.FALSE);
		String logFile = serverPrefs.getProperties("PhalanxServer.Logging.LogFile");
		
		serverLogger = new SystemLogger(logLevel);
		
		if (isLogToFile.booleanValue()){
			serverLogger.initializeFileLogger(logFile, logFileLevel);
		}
	}
	
	private void initializeCaches(){
		serverCache.createNewCache("UserCache", true, new UserCacheHandler(), true);
		serverCache.createNewCache("PhalanxMapCache", true, 
				new PhalanxMapCacheHandler(mapDir, defaultTileSet, cacheDir, mapMgr), true);
		serverCache.createNewCache("ExtendedUserInfoCache");
		serverCache.createNewCache("ActiveSessionCache"); // Cache for logged in users
		serverCache.createNewCache("TokenSessionCache"); // Cache for cookie based authentication
		serverCache.createNewCache("UserWebFeedCache"); // Cache for persistent web feeds under UserWebSession
		serverCache.createNewCache("GameListCache", true, new GameListCacheHandler(createDefaultUnitSet()), true);
		serverCache.createNewCache("UserGameCache", true, new GamePlayersCacheHandler(), true);
		serverCache.createNewCache("CurrentGameState", true, new PhalanxGameStateCacheHandler(), true);
		serverCache.createNewCache("PlayerStateCache", true, new PhalanxPlayerStateCacheHandler(), true);
		serverCache.createNewCache("UserChatCache");
		serverCache.createNewCache("PlayerMoveCache", true, new GameMoveCacheHandler(), true);
		serverCache.createNewCache("GameEngineCache");
		serverCache.createNewCache("PlayerTurnTimer");
		serverCache.createNewCache("GameFeedCache");
		
		// Read in all persistence caches
		serverLogger.writeToConsole("Populating Caches...", this, serverLogger.NORMAL);
		serverCache.populateCache("UserCache");
		serverCache.populateCache("PhalanxMapCache");
		serverCache.populateCache("GameListCache");
		serverCache.populateCache("UserGameCache");
		serverCache.populateCache("CurrentGameState");
		serverCache.populateCache("PlayerStateCache");
		serverCache.populateCache("PlayerMoveCache");
		serverLogger.writeToConsole("Caches fully loaded", this, serverLogger.NORMAL);

		setCachesLoaded(true);
	}
	
	public CacheManager getCacheManager(){
		return serverCache;
	}
	
	public ServerPreferences getServerPrefs(){
		return serverPrefs;
	}
	
	public String formattedVersion(){
		return majorVersion + "." + minorVersion + "." + subVersion;
	}
	
	public SystemLogger getServerLogger(){
		return serverLogger;
	}
	
	public PhalanxChatRoomManager getChatManager(){
		return chatMgr;
	}
	
	public PhalanxMapManager getMapManager(){
		return mapMgr;
	}

	private void setCachesLoaded(boolean cachesLoaded) {
		this.cachesLoaded = cachesLoaded;
	}

	public boolean isCachesLoaded() {
		return cachesLoaded;
	}
}
